import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
import { DesignerEnvType } from '../entity';
import { FormSchemaEntity, FormSchemaEntityField, FormSchemaEntityField$Type, FormSchemaEntityFieldType$Type } from '../entity/schema';
import { DomService } from './dom.service';
import { FormBasicService } from './form-basic.service';
import { FarrisMetadataService } from './metadata-service';

/**
 * 操作表单DOM Schema的工具类
 */
@Injectable({
    providedIn: 'root'
})
export class SchemaService {

    /** 控件工具箱拖拽产生的新增字段，用于零代码场景 */
    public addedFieldsByControlBox = [];

    /** 控件工具箱拖拽产生的关联字段，需要记录与be的关联关系，用于零代码场景 */
    public addedRelatedFieldsByControlBox = {};

    constructor(
        private domService: DomService,
        private metadataService: FarrisMetadataService,
        private formBasicService: FormBasicService,
        private http: HttpClient) { }

    getSchemaEntities(): FormSchemaEntity[] {
        const schema = this.domService.getSchemas();
        return schema.entities;
    }

    /**
     * 获取表字段列表
     * @param entities 实体对象集合
     * @param bindTo 实体绑定路径
     */
    getTableFieldsByBindTo(entities: FormSchemaEntity[], bindTo: string): FormSchemaEntityField[] {
        if (!entities || entities.length === 0) {
            return;
        }
        const splitIndex = bindTo.indexOf('/');
        if (splitIndex > -1) {
            bindTo = bindTo.slice(splitIndex + 1, bindTo.length);
        }

        for (const entity of entities) {
            const entityType = entity.type;
            if (!entityType) {
                return [];
            }
            if (bindTo === '' || bindTo === entity.code || bindTo === entity.label) {
                return entityType.fields;
            }
            if (entityType.entities && entityType.entities.length > 0) {
                const fields = this.getTableFieldsByBindTo(entityType.entities, bindTo);
                if (fields) {
                    return fields;
                }
            }
        }
    }

    private extractFieldsFromEntityType(entityType: { fields?: FormSchemaEntityField[] }) {
        const fields: FormSchemaEntityField[] = [];
        if (entityType && entityType.fields && entityType.fields.length) {
            entityType.fields.forEach(field => {
                if (field.$type === 'SimpleField') {
                    fields.push(field);
                } else {
                    const extractedFields = this.extractFieldsFromEntityType(field.type);
                    if (extractedFields.length) {
                        extractedFields.forEach(extractedField => fields.push(extractedField));
                    }
                }
            });
        }
        return fields;
    }

    /**
     * 根据bindTo获取对应表基本信息
     * @param viewModelId 数据模型标识
     */
    getTableInfoByViewModelId(viewModelId: string): { id: string, code: string, name: string, label: string } {
        const vm = this.domService.getViewModelById(viewModelId);
        const entities = this.getSchemaEntities();
        if (entities && entities.length > 0) {
            return this._getTableBasicInfoByUri(entities, vm.bindTo);
        }
    }

    /**
     * 根据bindTo获取对应表信息
     * @param entities 实体
     * @param bindTo VM绑定
     */
    private _getTableBasicInfoByUri(entities: FormSchemaEntity[], bindTo: string): any {
        if (!entities || entities.length === 0) {
            return;
        }
        const splitIndex = bindTo.indexOf('/');
        if (splitIndex > -1) {
            bindTo = bindTo.slice(splitIndex + 1, bindTo.length);
        }

        for (const entity of entities) {
            if (bindTo === '' || bindTo === entity.code || bindTo === entity.label) {
                return {
                    id: entity.id,
                    code: entity.code,
                    name: entity.name,
                    label: entity.label
                };
            }
            const entityType = entity.type;

            if (entityType && entityType.entities && entityType.entities.length > 0) {
                const basicInfo = this._getTableBasicInfoByUri(entityType.entities, bindTo);
                if (basicInfo) {
                    return basicInfo;
                }
            }
        }

    }

    /**
     * 根据VM id获取对应表名
     * @param viewModelId 实体模型标识
     */
    getTableCodeByViewModelID(viewModelId) {
        const vm = this.domService.getViewModelById(viewModelId);

        const entities = this.getSchemaEntities();
        if (entities && entities.length > 0) {
            return this._getTableCodeByUri(entities, vm.bindTo);
        }
        return '';
    }

    /**
     * 根据bindTo获取对应表名
     * @param entities 实体对象集合
     * @param bindTo 绑定路径
     */
    private _getTableCodeByUri(entities: FormSchemaEntity[], bindTo: string): string {
        if (!entities || entities.length === 0) {
            return;
        }
        const splitIndex = bindTo.indexOf('/');
        if (splitIndex > -1) {
            bindTo = bindTo.slice(splitIndex + 1, bindTo.length);
        }

        for (const entity of entities) {
            if (bindTo === '' || bindTo === entity.code || bindTo === entity.label) {
                return entity.code;
            }
            const entityType = entity.type;

            if (entityType && entityType.entities && entityType.entities.length > 0) {
                const code = this._getTableCodeByUri(entityType.entities, bindTo);
                if (code) {
                    return code;
                }
            }
        }
    }

    /**
     * 根据bindTo获取对应表名
     * @param entities 实体对象集合
     * @param bindTo 绑定路径
     */
    private _getTableLabelByUri(entities: FormSchemaEntity[], bindTo: string): string {
        if (!entities || entities.length === 0) {
            return;
        }
        const splitIndex = bindTo.indexOf('/');
        if (splitIndex > -1) {
            bindTo = bindTo.slice(splitIndex + 1, bindTo.length);
        }
        for (const entity of entities) {
            if (bindTo === '' || bindTo === entity.code || bindTo === entity.label) {
                return entity.label;
            }
            const entityType = entity.type;

            if (entityType && entityType.entities && entityType.entities.length > 0) {
                const label = this._getTableLabelByUri(entityType.entities, bindTo);
                if (label) {
                    return label;
                }
            }
        }
    }

    /**
     * 根据字段ID和ViewModelId获取字段信息（包括关联表字段）
     * 返回对象 {实体，是否关联字段，关联字段的dataField}
     * @param id 字段标识
     * @param viewModelId 视图模型标识
     */
    getFieldByIDAndVMID(id: string, viewModelId: string): {
        schemaField: FormSchemaEntityField, isRefElement: boolean, refElementLabelPath: string
    } {
        const entities = this.getSchemaEntities();
        if (!entities || entities.length === 0) {
            return;
        }
        const vm = this.domService.getViewModelById(viewModelId);
        const fields = this.getTableFieldsByBindTo(entities, vm.bindTo);
        if (!fields) {
            return;
        }
        return this.getFieldInfoByID(fields, '', id);
    }

    /**
     * 根据字段path和ViewModelId获取字段信息（包括关联表字段）
     * 返回对象 {实体，是否关联字段，关联字段的dataField}
     * @param path 字段标识
     * @param viewModelId 视图模型标识
     */
    getFieldByPathAndVMID(path: string, viewModelId: string): {
        schemaField: FormSchemaEntityField, isRefElement: boolean, refElementLabelPath: string
    } {
        const entities = this.getSchemaEntities();
        if (!entities || entities.length === 0) {
            return;
        }
        const vm = this.domService.getViewModelById(viewModelId);
        const fields = this.getTableFieldsByBindTo(entities, vm.bindTo);
        if (!fields) {
            return;
        }
        return this.getFieldInfoByPath(fields, '', path);
    }


    /**
     * 根据字段ID获取schema字段信息--用户旧表单适配
     */
    getFieldByID(fieldId: string) {
        const entities = this.getSchemaEntities();
        if (!entities || entities.length === 0) {
            return;
        }
        for (const viewModel of this.domService.viewmodels) {
            if (viewModel.bindTo === '/' && !viewModel.parent) {
                continue;
            }
            const fields = this.getTableFieldsByBindTo(entities, viewModel.bindTo);
            if (!fields) {
                continue;
            }
            const result = this.getFieldInfoByID(fields, '', fieldId);
            if (result && result.schemaField) {
                return result.schemaField;
            }
        }
    }


    /**
     * 递归查询字段
     * @param fields 实体字段集合
     * @param refElementLabelPath 字段路径
     * @param id 字段标识
     */
    getFieldInfoByID(fields: FormSchemaEntityField[], refElementLabelPath = '', id: string): {
        schemaField: FormSchemaEntityField, isRefElement: boolean, refElementLabelPath: string
    } {
        let element: FormSchemaEntityField; let isRefElement = false;
        const parentLabel = refElementLabelPath ? refElementLabelPath + '.' : '';
        for (const field of fields) {
            if (field.id === id) {
                element = field;
                refElementLabelPath = parentLabel + field.label;
                isRefElement = parentLabel ? true : false;
                break;
            } else {
                // 关联字段/UDT字段
                if (field.type && field.type.fields && field.type.fields.length > 0) {
                    const childResult = this.getFieldInfoByID(field.type.fields, parentLabel + field.label, id);
                    if (childResult.schemaField) {
                        element = childResult.schemaField;
                        refElementLabelPath = childResult.refElementLabelPath;
                        isRefElement = childResult.isRefElement;
                        break;
                    }
                }
            }
        }
        return { schemaField: element, isRefElement, refElementLabelPath };
    }

    /**
     * 递归查询字段
     * @param fields 实体字段集合
     * @param refElementLabelPath 字段路径
     * @param path 字段标识
     */
    getFieldInfoByPath(fields: FormSchemaEntityField[], refElementLabelPath = '', path: string): {
        schemaField: FormSchemaEntityField, isRefElement: boolean, refElementLabelPath: string
    } {
        let element: FormSchemaEntityField; let isRefElement = false;
        const parentLabel = refElementLabelPath ? refElementLabelPath + '.' : '';
        for (const field of fields) {
            if (field.path === path) {
                element = field;
                refElementLabelPath = parentLabel + field.label;
                isRefElement = parentLabel ? true : false;
                break;
            } else {
                // 关联字段/UDT字段
                if (field.type && field.type.fields && field.type.fields.length > 0) {
                    const childResult = this.getFieldInfoByID(field.type.fields, parentLabel + field.label, path);
                    if (childResult.schemaField) {
                        element = childResult.schemaField;
                        refElementLabelPath = childResult.refElementLabelPath;
                        isRefElement = childResult.isRefElement;
                        break;
                    }
                }
            }
        }
        return { schemaField: element, isRefElement, refElementLabelPath };
    }


    getTableLabelByVMID(viewModelId: string) {
        const entities = this.getSchemaEntities();
        if (!entities || entities.length === 0) {
            return;
        }
        const vm = this.domService.getViewModelById(viewModelId);
        return this._getTableLabelByUri(entities, vm.bindTo);
    }


    /**
     *  定位分级码字段（返回第一个类型为HierarchyType的字段）
     * @param viewModelId 视图模型标识
     */
    getTreeGridUdtField(viewModelId: string) {
        const entities = this.getSchemaEntities();
        if (!entities || entities.length === 0) {
            return;
        }
        const vm = this.domService.getViewModelById(viewModelId);
        const fields = this.getTableFieldsByBindTo(entities, vm.bindTo);
        if (!fields) {
            return '';
        }
        for (const element of fields) {
            if (element.type && element.type.$type === 'HierarchyType') {
                return element.label;
            }
        }
        return '';
    }

    /**
     *  获取分级码字段（返回所有类型为HierarchyType的字段）
     * @param viewModelId VMID
     */
    getTreeGridUdtFields(viewModelId: string): any[] {
        const entities = this.getSchemaEntities();
        if (!entities || entities.length === 0) {
            return;
        }
        const vm = this.domService.getViewModelById(viewModelId);
        const fields = this.getTableFieldsByBindTo(entities, vm.bindTo);
        const udtFields = [];
        if (!fields) {
            return [];
        }
        for (const element of fields) {
            if (element.type && element.type.$type === 'HierarchyType') {
                udtFields.push({ key: element.label, value: element.name });
            }
        }
        return udtFields;
    }

    /**
     * schema字段集合组装成树
     * @param fields schema字段集合
     */
    assembleFields2Tree(fields: FormSchemaEntityField[], expandRelateNode = true, displayedFieldsMap: Map<string, boolean> = null, label = '') {
        const treeData = [];
        fields.forEach(element => {
            // 零代码：不展示id等属性
            if (this.formBasicService && this.formBasicService.envType === DesignerEnvType.noCode &&
                ['id', "version", "processInstance", "parentID"].includes(element.bindingField)) {
                return;
            }
            // 补充bindingPath属性
            if (!element.bindingPath) {
                element.bindingPath = (label ? label + '.' : '') + element.label;
            }

            // 关联表字段 / UDT字段
            let children = [];
            if (element.type && element.type.fields && element.type.fields.length > 0) {
                children = this.assembleFields2Tree(element.type.fields, true, displayedFieldsMap, element.bindingPath);
            }

            treeData.push({
                data: element,
                children,
                expanded: expandRelateNode,
                selectable: children.length > 0 ? false : true,
                isUsed: displayedFieldsMap && displayedFieldsMap.has(element.id),
                tips: element.name + '[' + element.id + ']'
            });

        });
        return treeData;
    }

    /**
     * VO 转化为表单schema
     * @param voId 视图对象标识
     */
    converVO2Schema(voId: string, sessionId: string) {
        const subject = new Subject<any>();
        // 1、schema.id 查询VO实体
        this.metadataService.getMetadata(voId).subscribe(data => {
            if (data && data.content) {
                const voMetadataContent = JSON.parse(data.content);

                // 2、将VO实体转为schema
                const schemaUrl = '/api/dev/main/v1.0/designschema/create';
                this.http.post(schemaUrl, voMetadataContent, {
                    headers: new HttpHeaders({ 'Content-Type': 'application/json', SessionId: sessionId })
                }).subscribe(schema => {
                    subject.next(schema);
                }, error => {
                    subject.next();
                });
            }
        }, error => {
            subject.next();
        });
        return subject;
    }

    /**
     * 零代码设计器：VO 转化为表单schema
     */
    convertVoToSchemaForNoCodeForm(voId: string) {
        const schemaUrl = '/api/dev/main/v1.0/designschema/create';
        // const loadMetaDataURL = '/api/dev/nocode/v1.0/micro-apps/metadatas';

        const sessionId = '';
        const headerOptions = {
            headers: new HttpHeaders({ 'Content-Type': 'application/json', SessionId: sessionId })
        };

        const subject = new Subject<any>();
        const sortData = (data) => {

            if (data && data.content) {
                const voMetadataContent = JSON.parse(data.content);

                // todo 临时性代码，接口调整后需要删除
                const warpped = { isRuntime: true, viewObject: voMetadataContent };
                this.http.post(schemaUrl, warpped, headerOptions).subscribe(schema => {
                    subject.next(schema);
                }, error => {
                    subject.next();
                });
            }

        };

        // 零代码下 执行的是使用获取表单数据的接口
        this.metadataService.getMetadata(voId).subscribe(sortData, error => {
            subject.next();
        });
        return subject;
    }

    /**
     * 获取指定VM下的所有字段
     * @param viewModelId 视图模型标识
     */
    getFieldsByViewModelId(viewModelId: string): FormSchemaEntityField[] {
        const vm = this.domService.getViewModelById(viewModelId);
        if (!vm) {
            return [];
        }
        const entities = this.getSchemaEntities();
        if (!entities || entities.length === 0) {
            return;
        }
        return this.getTableFieldsByBindTo(entities, vm.bindTo);
    }


    /**
     * 根据实体获取VM id，之前用于实体树的拖拽
     * @param entity 实体
     */
    getViewModelIdByEntity(entity: FormSchemaEntity): string {
        if (!entity) {
            return void 0;
        }
        const viewModels = this.domService.viewmodels;
        const entities = this.getSchemaEntities();
        const mappingViewModel = viewModels.find(viewModel => {
            if (viewModel.id === 'root-viewmodel') {
                return false; // root viewmodel 不对应任何SchemaEntity
            }
            const info = this._getTableBasicInfoByUri(entities, viewModel.bindTo);
            return info.id === entity.id;
        });
        // 找到对应的viewmodel返回id，找不到返回undefined。
        return mappingViewModel && mappingViewModel.id;
    }

    /**
     * 根据指定的字段key值，获取字段信息。例如获取key=bindingPath,值为xxx的字段
     * @param targetFieldKey 字段key
     * @param targetFieldValue 字段key值
     */
    public getSchemaField(targetFieldKey: string, targetFieldValue: string): FormSchemaEntityField | null {
        const entities = this.getSchemaEntities();
        let retField: FormSchemaEntityField;
        const getTargetFiled = (predicate: (element: FormSchemaEntityField) => {}, fieldsArray: FormSchemaEntityField[]) => {
            fieldsArray.find((element: FormSchemaEntityField) => {
                const predicateResult = predicate(element);
                if (predicateResult) {
                    retField = element;
                    return true;
                } else {
                    if (element.type.fields) {
                        getTargetFiled(predicate, element.type.fields);
                    }
                }
                return false;
            });
        };
        entities.forEach((entitiesItem: FormSchemaEntity) => {
            getTargetFiled((field: FormSchemaEntityField) => field[targetFieldKey] === targetFieldValue, entitiesItem.type.fields);
        });

        return retField;
    }

    /**
     * 字段名称映射更改
     */
    public fieldsDisplayNameUpdate(entity: FormSchemaEntityField[]) {
        entity.forEach((item) => {
            if (item.$type === FormSchemaEntityField$Type.SimpleField) {
                switch (item.type.$type) {
                    case FormSchemaEntityFieldType$Type.NumericType:
                        if (item.type.precision === 0) {
                            item.type.displayName = '整数';
                        }
                        if (item.type.precision > 0) {
                            item.type.displayName = '浮点数字';
                        }
                        break;
                    case FormSchemaEntityFieldType$Type.StringType:
                        item.type.displayName = '文本';
                        break;
                    case FormSchemaEntityFieldType$Type.TextType:
                        item.type.displayName = '备注';
                        break;

                    default:
                        break;
                }

            }
        });
    }

    /**
     * 删除schema实体
     * @param entityId 实体id
     */
    public deleteSchemaEntityById(entityId: string) {

        const schemaEntities = this.getSchemaEntities();
        if (!schemaEntities || schemaEntities.length < 1 || !schemaEntities[0]) {
            return;
        }
        const mainEntity = schemaEntities[0];
        const queue = [mainEntity];
        while (queue.length) {
            const current = queue.shift();

            if (current.type.entities && current.type.entities.length) {
                if (current.type.entities.some(entity => entity.id === entityId)) {
                    current.type.entities = current.type.entities.filter(entity => entity.id !== entityId);
                    return;
                }
                queue.push(...current.type.entities);
            }

        }

    }

    /**
     * 触发删除schema中的字段。
     * 场景：零代码中工具箱拖拽输入类控件会自动新增字段，所以在删除控件的时候需要将字段一起删除。
     * @param fieldIdList 待删除的字段列表
     */
    removeSchemaField(fieldIdList: string[]) {
        if (!fieldIdList || !fieldIdList.length) {
            return;
        }
        fieldIdList.forEach(targetFieldId => {

            // 判断删除的字段是新增的字段还是已保存到元数据中的字段
            if (this.addedFieldsByControlBox.length) {
                if (this.addedFieldsByControlBox.some(id => id === targetFieldId)) {

                    let entityInfo = this.getFieldBelongedEntity(targetFieldId);
                    if (!entityInfo) {
                        return;
                    }
                    // 若是关联字段，则需要定位到关联的根节点，然后从所属实体中将根节点删除
                    if (entityInfo.isRefElement) {
                        const belongedEntity = entityInfo.entity;
                        const bindingPath = entityInfo.schemaField.bindingPath;
                        const refRootLabel = bindingPath.slice(0, bindingPath.indexOf('.'));
                        const refRootFieldIndex = belongedEntity.type.fields.findIndex(field => field.bindingPath === refRootLabel);
                        if (refRootFieldIndex > -1) {
                            const refFieldId = belongedEntity.type.fields[refRootFieldIndex].id;
                            delete this.addedRelatedFieldsByControlBox[refFieldId];

                            belongedEntity.type.fields.splice(refRootFieldIndex, 1);

                        }

                    } else {
                        // 若是简单字段，可以直接按照id删除
                        const belongedEntity = entityInfo.entity;
                        belongedEntity.type.fields = belongedEntity.type.fields.filter(field => field.id !== targetFieldId);
                    }

                    this.addedFieldsByControlBox = this.addedFieldsByControlBox.filter(fieldId => fieldId !== targetFieldId);
                }
            }
        })

    }


    /**
     * 根据视图模型id删除绑定的schema实体
     * @param viewModelId 视图模型id
     */
    removeSchemaEntityByViewModelId(viewModelId: string) {

        if (this.addedFieldsByControlBox && this.addedFieldsByControlBox.length) {
            const belongedEntityInfo = this.getTableInfoByViewModelId(viewModelId);
            if (!belongedEntityInfo) {
                return;
            }
            // 若当前列表绑定的实体是通过控件树新增的，那么在删除列表时将实体一起删除
            if (this.addedFieldsByControlBox.some(id => id === belongedEntityInfo.id)) {

                this.deleteSchemaEntityById(belongedEntityInfo.id);

                this.addedFieldsByControlBox = this.addedFieldsByControlBox.filter(fieldId => fieldId !== belongedEntityInfo.id);
            }
        }
    }

    /**
     * 根据字段id获取所属schema实体和字段
     * @param fieldId 字段id
     */
    private getFieldBelongedEntity(fieldId: string): {
        entity: FormSchemaEntity, schemaField: FormSchemaEntityField, isRefElement: boolean
    } {
        const schemaEntities = this.getSchemaEntities();
        if (!schemaEntities || schemaEntities.length < 1 || !schemaEntities[0]) {
            return null;
        }
        const mainEntity = schemaEntities[0];
        let queue = [mainEntity];
        while (queue.length) {
            const current = queue.shift();
            if (current.type.fields && current.type.fields.length) {

                const fieldInfo = this.getFieldInfoByID(current.type.fields, '', fieldId);
                if (fieldInfo) {
                    return {
                        entity: current,
                        schemaField: fieldInfo.schemaField,
                        isRefElement: fieldInfo.isRefElement
                    }
                }
            }
            if (current.type.entities && current.type.entities.length) {
                queue = queue.concat(current.type.entities);
            }
        }
        return null;
    }
}
